package cn.lg.soar.mvc.config.jackson;

import cn.lg.soar.common.util.DatetimeUtil;
import cn.lg.soar.common.util.jackson.ProjectJacksonAnnotationIntrospector;
import cn.lg.soar.common.util.jackson.deserializer.*;
import cn.lg.soar.common.util.jackson.serializer.*;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jackson.JacksonProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
* 配置spring boot内嵌的Jackson序列化与反序列化类型映射
*
*  -LocalDateTime类型转换为毫秒值：解决苹果前端兼容问题
*  -Long类型转为字符串：解决Long类型数据返回到前端精度丢失问题
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Configuration
@ConditionalOnProperty(value = "lg.enabled.json-converter", havingValue = "true", matchIfMissing = true)
public class JacksonSerializerConfig {

    @Autowired
    private JacksonProperties properties;

    @Value("${spring.jackson.local-date:yyyy-MM-dd}")
    private String datePattern;

    @Value("${spring.jackson.local-time:HH:mm:ss}")
    private String timePattern;

    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        String dateFormat = properties.getDateFormat();
        DateTimeFormatter formatter;
        if (dateFormat == null) {
            dateFormat = DatetimeUtil.PATTERN;
        }
        formatter = DateTimeFormatter.ofPattern(dateFormat);
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(datePattern);
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(timePattern);

        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        SimpleModule simpleModule = new SimpleModule();
        // 添加自定义序列化器
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Enum.class, EnumSerializer.instance);
        simpleModule.addSerializer(LocalDate.class, new SLocalDateSerializer(dateFormatter));
        simpleModule.addSerializer(LocalTime.class, new SLocalTimeSerializer(timeFormatter));
        simpleModule.addSerializer(LocalDateTime.class, new SLocalDateTimeSerializer(formatter));
        simpleModule.addSerializer(Date.class, new SDateSerializer(dateFormat));

        // 添加自定义反序列化器
        simpleModule.addDeserializer(Enum.class, EnumDeserializer.instance);
        simpleModule.addDeserializer(LocalDate.class, new SLocalDateDeserializer(dateFormatter));
        simpleModule.addDeserializer(LocalTime.class, new SLocalTimeDeserializer(timeFormatter));
        simpleModule.addDeserializer(LocalDateTime.class, new SLocalDateTimeDeserializer(formatter));
        simpleModule.addDeserializer(Date.class, new SDateDeserializer(dateFormat));

        objectMapper.registerModule(simpleModule);

        // 添加内省器（自定义注解功能实现）
        AnnotationIntrospector sis = objectMapper.getSerializationConfig().getAnnotationIntrospector();
        AnnotationIntrospector is1 = AnnotationIntrospectorPair.pair(sis, new ProjectJacksonAnnotationIntrospector());
        objectMapper.setAnnotationIntrospector(is1);

        return objectMapper;
    }
}
